package com.hspedu.hspspringmvc.servlet;

import com.hspedu.hspspringmvc.annotation.Controller;
import com.hspedu.hspspringmvc.annotation.RequestMapping;
import com.hspedu.hspspringmvc.context.HspWebApplicationContext;
import com.hspedu.hspspringmvc.handler.HspHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * packageName com.hspedu.hspspringmvc.servlet
 *
 * @author 你的名字
 * @version JDK 8
 * @className HspDispatcherServlet (此处以class为例)
 * @date 2025/2/11
 * @description TODO
 */
public class HspDispatcherServlet extends HttpServlet {

    private HspWebApplicationContext hspWebApplicationContext;

    private List<HspHandler> hspHandlers = new ArrayList<>();



    @Override
    public void init() throws ServletException {
        String contextConfigLocation
                = getServletConfig().getInitParameter("contextConfigLocation");
        hspWebApplicationContext = new
                HspWebApplicationContext(contextConfigLocation);
        hspWebApplicationContext.init();
        initHandlerMapping();
        System.out.println("hsphandlers:"+hspHandlers);
    }


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        executeDispatch(req,resp);
    }

    /**
     * 初始化处理器映射
     * 此方法遍历IoC容器中的所有Bean，寻找标记为@Controller的类，并解析其@RequestMapping注解，
     * 以建立URL到方法的映射关系
     */
    public void initHandlerMapping(){
        // 如果IoC容器为空，则直接返回，不进行处理
        if (hspWebApplicationContext.ioc.isEmpty()){
            return ;
        }
        // 遍历IoC容器中的所有Bean
        for (Map.Entry<String, Object> entry : hspWebApplicationContext.ioc.entrySet()) {
            // 获取当前Bean的类信息
            Class<?> aClass = entry.getValue().getClass();
            // 检查当前类是否标记为@Controller注解
            if (aClass.isAnnotationPresent(Controller.class)){
                // 获取当前类的所有声明的方法
                Method[] declaredMethods = aClass.getDeclaredMethods();
                // 遍历所有方法，寻找标记为@RequestMapping注解的方法
                for (Method method : declaredMethods) {
                    // 检查当前方法是否标记为@RequestMapping注解
                    if (method.isAnnotationPresent(RequestMapping.class)){
                        // 获取@RequestMapping注解实例
                        RequestMapping annotation
                                = method.getAnnotation(RequestMapping.class);
                        // 获取映射的URL路径
                        String value = annotation.value();
                        // 创建处理器对象，封装URL路径、控制器实例和方法名
                        HspHandler hspHandler = new HspHandler(value, entry.getValue(), method);
                        // 将处理器对象添加到处理器映射中
                        hspHandlers.add(hspHandler);
                    }
                }
            }
        }
    }

    /**
     * 根据 request 请求，返回对应的 HspHandler 对象
     * @param request
     * @return
     */
    private HspHandler getHspHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        for (HspHandler hspHandler : hspHandlers) {
            if (requestURI.equals(hspHandler.getUrl())){
                return hspHandler;
            }

        }
        return null;

    }

    /**
     * executeDispatch 完成请求的分发处理, 在 doPost 调用(所有的请求都会走
     doPost)
     * @param req
     * @param response
     */
    private void executeDispatch(HttpServletRequest req,
                                 HttpServletResponse response) {
        System.out.println("执行请求分发");
        HspHandler hspHandler = getHspHandler(req);
        try {
            if (hspHandler != null){
                hspHandler.getMethodName()
                        .invoke(hspHandler.getController(),req,response);
            }else {
                response.getWriter().print("<h1>404 Not Found</h1>");
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

}
